iT邦幫忙

2023 iThome 鐵人賽

DAY 11
1
Modern Web

深入淺出,完整認識 Next.js 13 !系列 第 11

Day 11 - Next.js 13 App Router :什麼時候適合使用 Server Components 或 Client Components?

  • 分享至 

  • xImage
  •  

昨天我們介紹了 Server Components 和 Client Compnents 是什麼,這時你可能會問,所以使用 Server Components 的優點是什麼?我該怎麼選用兩者呢?

使用 Serve Components 優點主要有以下幾項:

  1. 降低傳回 client-side 的 JS bundle 大小
  2. 提升敏感資料的保密性
  3. 提升與後端服務互動的頻率
  4. 減少重複渲染次數
  5. 更簡單地實現 streaming

降低傳回 client-side 的 JS bundle 大小

假如只有在 Server Components 中用到的程式碼與 dependencies, 在 server-side 渲染完 components 後,不會被傳回 client,因此可以降低 client 需下載的 JS bundle 大小,加快頁面 initial loading。

提升敏感資料的保密性

也因為部分程式碼、資料不會被傳回到 client,我們可以將一些 client 不會使用到,且較機密的資料 (ex: API key, access token 等等 ) 留在 server,提升資料的隱密性。

提升與後端服務互動的頻率

比起 client-side 渲染,server-side 渲染也意味著,渲染環境較靠近 database,所以在其他條件 ( ex: 網路、設備品質 ) 相同的狀況下,後端服務的延遲會較低,連線速度也會較快。

減少重複渲染次數

為了盡量減少 server 做重複的事情,假如目前路由的內容是可以靜態渲染的,意思是不需要使用 cookies、網址的 search paramrs 等機制提供客製化的 HTML 給用戶,Next 預設會在 build time 渲染頁面,並快取渲染結果,假如收到相同 request,就可以重複使用渲染好的靜態檔案,不用重新渲染一次,可以加快 server response 的速度與減輕 server 負擔。

那假如要動態渲染呢,比方說我會依據 cookies 決定頁面內容?那 Next 就會在收到 client request 時執行渲染。

這樣的意思是,我們必須去定義每個 route 要靜態渲染還動態渲染嗎?不用不用,Next 預設會使用靜態渲染,假如 route 有使用 dynamic functions 或是 uncached data request 會自動轉成動態渲染!

Dynamic functions 包含 cookies()headers()useSearchParams()searchParams

Uncached Data Request 是指不會被快取的 fetch request。為了能避免不必要地重複 data fetching,Next 擴充了 Web API 裡的 fetch API,讓 fetch 結果可以存快取,重複使用。但有些情況我們可能不希望儲存 fetch result,那我們就可以手動做些設定,例如在 fetch 後加入cache: 'no-store'

fetch('https://...', { cache: 'no-store' })

Next.js 的快取機制會在 Day 28Day 29 詳細介紹

更簡單地實現 Streaming

React 18 針對提升 Server-Side Rendering 的使用者體驗,推出了 Streaming 的功能。簡單來說,開發者可以將頁面拆成不同片段 ( boundaries ),React 會將渲染好的片段先傳給 client,來讓使用者在有 components 還沒渲染完時,先看到渲染好的部分,不必等到所有 components 渲染完才看得到頁面,減少使用者首次拜訪頁面時,等待畫面出現的時間。而 Server Components 則讓開發者可以用 components 當作 streaming boundaries。後續文章會再教大家實作。
streaming
( 圖片來源:https://nextjs.org/docs/app/building-your-application/rendering/server-components )

但要享受這些好處,一定會有些 trade-off:

Server Components 只能是「靜態」的

Server Components 無法使用 props、state、event listeners (ex: onClick(), onChange() 等等 ) 或像是 useState、useEffect、useReducer 等 React hooks。這也意味著 Server Components 無法含有互動成分,只能是純靜態的 components。

假如在 Server Components 中使用了上述 client-side only 的功能,例如使用 useState,終端機和瀏覽器會跳出 useState 只能在 Client Components 使用的錯誤提示。
https://ithelp.ithome.com.tw/upload/images/20230911/20161853K0JruEnWfj.png

你可能會問:在 Client Components 中,我們可以透過 state 和 props 的改變來觸發 re-rendering。那 Server Components 不能使用 state 和 props,要怎麼觸發 re-rendering 呢?

我們可以透過 useRouter 的其中一個 method - router.refresh()在不重置 React state 和瀏覽器狀態 ( ex: 目前滾輪位置 )下,讓瀏覽器重新向 server 發一次 request,讓 Server Components 重新渲染。 後續會路由篇會再介紹。

無法使用 Client-Only 功能

因為 Server Components 渲染環境在 server,無法使用像 window、local storage 等 client-side 才能使用的功能。

無法使用 CSS-in-JS

目前大部分的 CSS-in-JS libraries,像是 Styled Components,不支援 Server Components。官方說法,Next 和 React 團隊正積極與這些 libraries 的團隊合作產生可用的 API,所以假如習慣使用 CSS-in-JS 的朋友,可能要再忍耐一下。

做個總結,什麼時候適合使用 Server Components 呢?當 components 中需要 fetch data、與後端服務互動,或有機密資料不想傳回 client-side,又不會使用到 state、props、React hooks、brower-only APIs 時,Server Components 就會是個好選擇;反之則可使用 Client Components。
https://ithelp.ithome.com.tw/upload/images/20230911/20161853lEhuLMI5iW.png
( 圖片來源:https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns )

App Router 中,Next 預設所有 components 都是 Server Components,假如想轉為 Client Components,只需要在檔案最上方加入一段 'use client'

'use client'
 
import { useState } from 'react'
 
export default function Counter() {
  const [count, setCount] = useState(0)
 
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}

所以只要某個 component 中,含有 client-only 的功能,就必須整個 component 都轉為 Client Components 嗎?每個 Client Components 都要加上 use client 嗎?

明天就來解答這兩個問題,並大家分享幾個 Server Components 和 Client Components 使用上官方提供的 best practices 吧!

謝謝大家耐心的閱讀,我們明天見!


上一篇
Day 10 - Server Components 是什麼?跟 Server Side Rendering 一樣嗎?
下一篇
Day 12 - Next.js 13 Server Components 和 Client Components 組合使用該注意什麼?
系列文
深入淺出,完整認識 Next.js 13 !30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言